import applyMixin from './mixin';
import { forEachValue } from './util';

export let Vue;

// vuex容器的初始化
export class Store {
  constructor(options) { // options 就是执行 new Vuex.store({state, mutation, actions})
    const { state } = options; // 数据变化更新视图(vue的核心依赖收集)

    // 响应式数据new Vue({data})

    // 1.添加状态逻辑 数据在哪里使用 就会收集对应的依赖
    const computed = {};

    // 2.处理getters属性 具有缓存的 computed就是带有缓存的(多次取值，如果值不变是不会重新调用的)
    this.getters = {};
    forEachValue(options.getters, (fn, key) => {
      computed[key] = () => fn(this.state); // 将用户的getters定义在实例上
      Object.defineProperty(this.getters, key, { // 当取值的时候执行计算属性的逻辑
        get: () => this._vm[key],
      });
    });
    // 3.计算属性的实现
    this._vm = new Vue({
      data: { // 属性如果是通过$开头的， 默认不会讲这个属性挂在到vm实例上
        $$state: state, // 会将$$state对应的对象 都通过defineProperty来进行属性劫持
      },
      computed,
    });

    // 4.mutations的实现
    this.mutations = {};
    this.actions = {};
    forEachValue(options.mutations, (fn, key) => {
      this.mutations[key] = (payload) => fn(this.state, payload);
    });

    forEachValue(options.actions, (fn, key) => {
      this.actions[key] = (payload) => fn(this, payload);
    });
  }

  // vuex中的commit方法
  commit = (type, payload) => { // 保证当前this指向store实例
    // 调用commit其实就是去找刚才绑定好的mutation
    this.mutations[type](payload);
  }

  // 5.actions的实现
  dispatch = (type, payload) => { // vuex中的dispatch方法
    this.actions[type](payload);
  }
  // 6.模块的实现

  get state() {
    return this._vm._data.$$state;
  }
}

// Vue.use方法会调用插件的install方法，此方法中的参数就是Vue的构造函数
export const install = (_Vue) => { // vuex插件的安装 Vue.use()
  // _Vue 是Vue的构造函数
  Vue = _Vue;

  // 需要将根组件中注入的store 分派给每一个组件(子组件)
  applyMixin(Vue);
};
